#pragma once

#include <iostream>
#include <queue>
#include <pthread.h>

static const int gcap = 5;

template <class T>
class BlockQueue
{
public:
    BlockQueue(const int cap = gcap) : _cap(cap)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_consumer_cond, nullptr);
        pthread_cond_init(&_productor_cond, nullptr);
    }

    bool isEmpty()
    {
        return _q.empty();
    }

    bool isFull()
    {
        return _q.size() == _cap;
    }

    void push(const T &in)
    {
        pthread_mutex_lock(&_mutex);
        while (isFull()) // 判断是否满足生产条件，缓冲区满了不能进行生产
        {
            pthread_cond_wait(&_productor_cond, &_mutex);
        }
        // 生产数据
        _q.push(in);
        // 唤醒消费者，可加唤醒策略
        pthread_cond_signal(&_consumer_cond);
        pthread_mutex_unlock(&_mutex);
    }

    void pop(T *out)
    {
        pthread_mutex_lock(&_mutex);
        while (isEmpty()) // 判断是否满足消费条件，缓冲区为空不能进行消费
        {
            pthread_cond_wait(&_consumer_cond, &_mutex);
        }
        // 消费数据
        *out = _q.front();
        _q.pop();
        // 唤醒生产者，可加唤醒策略
        pthread_cond_signal(&_productor_cond);
        pthread_mutex_unlock(&_mutex);
    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_consumer_cond);
        pthread_cond_destroy(&_productor_cond);
    }

private:
    std::queue<T> _q;
    int _cap; // capacity 容量
    pthread_mutex_t _mutex;
    pthread_cond_t _consumer_cond;
    pthread_cond_t _productor_cond;
};